#include "TinyJsonReader.h"
#include "Array.h"
#include "Object.h"
#include <cassert>
#include <queue>
#include <cstring>
#include <fstream>

namespace tinyjson
{
    //加载待解析的字符串
    void TinyJsonReader::load_from_string(const char *json)
    {
        m_input = std::make_shared<std::istringstream>(json);
        // m_input.str(std::string(json));
    }

    void TinyJsonReader::load_from_file(const char *filepath)
    {
        std::ifstream file(filepath);
        assert(file.is_open());

        std::ostringstream out;
        out << file.rdbuf();

        m_input = std::make_shared<std::istringstream>(out.str());
        // m_input.str(out.str());
        file.close();
    }

    //判断流input的开头1个字符(去除空白字符)是否是字符ch
    //如果是,input跨过这1个字符，返回true
    Boolean TinyJsonReader::try_match_char(std::istream &input, char ch)
    {
        input >> std::ws;
        if (input.good() && !input.eof())
        {
            char ch1 = input.peek();
            if (ch == ch1)
            {
                input.get(ch);
                return true;
            }
            else
            {
                return false;
            }
        }
        return false;
    }

    //判断流input的开头几个字符(去除空白字符)是否是字符串src
    //如果是,input跨过这几个字符，返回true
    Boolean TinyJsonReader::try_match_string(std::istream &input, const String &src)
    {

        input >> std::ws;
        //存放匹配的字符串
        std::queue<char> buffer;

        size_t len = src.length();
        size_t cnt = 0;
        bool bSuccess = true;
        char ch = 0;

        //如果input中有字符，且没有匹配到字符串src
        while (input.good() && len > 0)
        {
            input.get(ch);
            if (input.eof())
            {
                bSuccess = false;
                break;
            }

            //如果单个字符匹配,更新索引
            if (src[cnt] == ch)
            {
                buffer.push(ch);
                len--;
                cnt++;
            }
            //如果单个匹配失败，恢复input
            else
            {
                input.putback(ch);
                bSuccess = false;
                break;
            }
        }

        //如果匹配失败，恢复input
        if (bSuccess == false)
        {
            while (!buffer.empty() && input.good())
            {
                input.putback(buffer.front());
                buffer.pop();
            }
        }
        return bSuccess;
    }

    Boolean TinyJsonReader::isdigit_1to9(const char ch)
    {
        return ch >= '1' && ch <= '9';
    }

    //解析4位16进行数，保存到u中
    //如果input中有"ABCD",则u=0xABCD
    Boolean TinyJsonReader::parse_hex4(std::istream &input, unsigned int &u)
    {
        int i;
        u = 0;
        char ch = 0;
        for (i = 0; i < 4; i++)
        {
            input.get(ch);
            u <<= 4;
            if (ch >= '0' && ch <= '9')
                u |= ch - '0';
            else if (ch >= 'A' && ch <= 'F')
                u |= ch - ('A' - 10);
            else if (ch >= 'a' && ch <= 'f')
                u |= ch - ('a' - 10);
            else
                return false;
        }
        return true;
    }

    //将unicode码点编码成UTF-8，保存到u中
    void TinyJsonReader::encode_utf8(String &buffer, unsigned int u)
    {
        if (u <= 0x7F)
            buffer.push_back(u & 0xFF);
        else if (u <= 0x7FF)
        {
            buffer.push_back(0xC0 | ((u >> 6) & 0xFF));
            buffer.push_back(0x80 | (u & 0x3F));
        }
        else if (u <= 0xFFFF)
        {
            buffer.push_back(0xE0 | ((u >> 12) & 0xFF));
            buffer.push_back(0x80 | ((u >> 6) & 0x3F));
            buffer.push_back(0x80 | (u & 0x3F));
        }
        else
        {
            assert(u <= 0x10FFFF);
            buffer.push_back(0xF0 | ((u >> 18) & 0xFF));
            buffer.push_back(0x80 | ((u >> 12) & 0x3F));
            buffer.push_back(0x80 | ((u >> 6) & 0x3F));
            buffer.push_back(0x80 | (u & 0x3F));
        }
    }

    //解析unicode字符
    Boolean TinyJsonReader::parse_unicode_string(std::istream &input, String &buffer)
    {
        unsigned int u = 0;
        unsigned int u2 = 0;
        char ch = 0;
        //解析4位16进行数，保存到u中
        if (!parse_hex4(input, u))
            return false;
        //如果unicode是代理码点，则解析出完成的unicode码点
        if (u >= 0xD800 && u <= 0xDBFF)
        {
            input.get(ch);
            if (ch != '\\')
                return false;
            input.get(ch);
            if (ch != 'u')
                return false;
            if (!parse_hex4(input, u2))
                return false;
            if (u2 < 0xDC00 || u2 > 0xDFFF)
                return false;
            u = (((u - 0xD800) << 10) | (u2 - 0xDC00)) + 0x10000;
        }
        //将unicode码点编码成UTF-8，保存到u中
        encode_utf8(buffer, u);
        return true;
    }

    const TinyJsonParseRet TinyJsonReader::parse_state() const
    {
        return m_status;
    }

    TinyJsonValue TinyJsonReader::parse_result()
    {
        return *m_value;
    }

    const TinyJsonValue TinyJsonReader::parse_result() const
    {
        return *m_value;
    }

    void TinyJsonReader::parse()
    {
        if (m_value == nullptr)
        {
            m_value = TinyJsonValue::create_tinyjsonvalue();
        }
        else
        {
            m_value->reset();
        }
        m_status = parse(*m_input, *m_value);
    }

    TinyJsonParseRet TinyJsonReader::parse(std::istream &input, TinyJsonValue &value)
    {
        TinyJsonParseRet ret;
        ret = parse_tinyjsonvalue(input, value);
        if (ret == TinyJsonParseRet::TINY_JSON_PARSE_SECCESS)
        {
            //判断解析成功后，input后面是否还有字符
            if (!input.eof())
            {
                input >> std::ws;
                if (!input.eof())
                {
                    value.set_type(TinyJsonType::TINY_JSON_EMPTY);
                    ret = TinyJsonParseRet::TINY_JSON_PARSE_FAIL;
                }
            }
        }
        return ret;
    }

    TinyJsonParseRet TinyJsonReader::parse_tinyjsonvalue(std::istream &input, TinyJsonValue &value)
    {
        assert(input.good());
        input >> std::ws;
        //如果input为空，则解析失败
        if (input.eof())
        {
            return TinyJsonParseRet::TINY_JSON_PARSE_FAIL;
        }
        else
        {
            //根据第一个非空白字符，判断是那种类型的json
            char ch = input.peek();
            switch (ch)
            {
            case 'n':
                return parse_literal(input, "null", value);
                break;
            case 't':
                return parse_literal(input, "true", value);
                break;
            case 'f':
                return parse_literal(input, "false", value);
                break;
            case '\"':
                return parse_string(input, value);
                break;
            case '[':
                return parse_array(input, value);
                break;
            case '{':
                return parse_object(input, value);
                break;
            default:
                return parse_number(input, value);
                break;
            }
        }
    }

    TinyJsonParseRet TinyJsonReader::parse_literal(std::istream &input, const char *literal, TinyJsonValue &value)
    {
        //判断input开头是否与literal匹配
        if (!try_match_string(input, literal))
        {
            return TinyJsonParseRet::TINY_JSON_PARSE_FAIL;
        }
        else
        {
            if (strcmp(literal, "null") == 0)
            {
                value.set_type(TinyJsonType::TINY_JSON_NULL);
            }
            else if (strcmp(literal, "true") == 0)
            {
                value.set_type(TinyJsonType::TINY_JSON_TRUE);
            }
            else if (strcmp(literal, "false") == 0)
            {
                value.set_type(TinyJsonType::TINY_JSON_FALSE);
            }
            return TinyJsonParseRet::TINY_JSON_PARSE_SECCESS;
        }
    }

    TinyJsonParseRet TinyJsonReader::parse_number(std::istream &input, TinyJsonValue &value)
    {
        std::streampos rollback = input.tellg();
        double number = 0;
        //解析数字
        input >> number;
        //数值超出double，input.fail()为true
        if (input.fail())
        {
            input.clear();
            input.seekg(rollback);
            return TinyJsonParseRet::TINY_JSON_PARSE_FAIL;
        }
        else
        {
            //根据json的数字规则，进一步判断是否是数字
            //下面的代码使input指向第一个不为数字的字符
            input.seekg(rollback);
            char c;
            // input.get(c);
            //  检查是否有负号
            if (input.peek() == '-')
            {
                input.get(c);
            }

            // 检查整数部分是否为0，或者1-9开头
            if (input.peek() == '0')
            {
                input.get(c);
            }
            else
            {
                // 检查是否为1-9开头的数字
                if (!isdigit_1to9(input.peek()))
                {
                    return TinyJsonParseRet::TINY_JSON_PARSE_FAIL;
                }
                //当读到EOF时，input.peek()返回-1
                while (isdigit(input.peek()))
                {
                    input.get(c);
                }
            }

            // 检查是否有小数点
            if (input.peek() == '.')
            {
                input.get(c);
                if (!std::isdigit(input.peek()))
                {
                    // 小数点后至少要有一个数字
                    return TinyJsonParseRet::TINY_JSON_PARSE_FAIL;
                }
                // 跳过小数点后的数字部分
                while (isdigit(input.peek()))
                {
                    input.get(c);
                }
            }

            // 检查是否有指数部分
            if (input.peek() == 'e' || input.peek() == 'E')
            {
                input.get(c);
                if (input.peek() == '+' || input.peek() == '-')
                {
                    input.get(c);
                }
                if (!std::isdigit(input.peek()))
                {
                    // 指数后面必须是数字
                    return TinyJsonParseRet::TINY_JSON_PARSE_FAIL;
                }
                // 跳过指数部分的数字
                while (isdigit(input.peek()))
                {
                    input.get(c);
                }
            }

            value.set_type(TinyJsonType::TINY_JSON_NUMBER);
            value.m_values.m_number_value = number;
            return TinyJsonParseRet::TINY_JSON_PARSE_SECCESS;
        }
    }

    TinyJsonParseRet TinyJsonReader::parse_string(std::istream &input, TinyJsonValue &value)
    {
        char ch = 0;
        char delimiter = '\"';
        //判断input第一个非空白字符是否是"
        if (!try_match_char(input, delimiter))
            return TinyJsonParseRet::TINY_JSON_PARSE_FAIL;
        ch = input.peek();
        //如果是空字符串("\"\"")
        if (ch == delimiter)
        {
            input.get(ch);
            value.set_type(TinyJsonType::TINY_JSON_STRING);
            value.m_values.m_string_value = std::make_shared<String>("");
            return TinyJsonParseRet::TINY_JSON_PARSE_SECCESS;
        }
        else
        {
            //存储解析的字符串
            String buffer;
            //解析字符串
            while (!input.eof() && input.good())
            {
                input.get(ch);
                switch (ch)
                {
                //表示字符串解析完毕
                case '\"':
                    value.set_type(TinyJsonType::TINY_JSON_STRING);
                    value.m_values.m_string_value = std::make_shared<String>(buffer);
                    return TinyJsonParseRet::TINY_JSON_PARSE_SECCESS;
                    break;
                //表示是转义字符
                case '\\':
                    input.get(ch);
                    switch (ch)
                    {
                    case '\"':
                        buffer.push_back('\"');
                        break;
                    case '\\':
                        buffer.push_back('\\');
                        break;
                    case '/':
                        buffer.push_back('/');
                        break;
                    case 'b':
                        buffer.push_back('\b');
                        break;
                    case 'f':
                        buffer.push_back('\f');
                        break;
                    case 'n':
                        buffer.push_back('\n');
                        break;
                    case 'r':
                        buffer.push_back('\r');
                        break;
                    case 't':
                        buffer.push_back('\t');
                        break;
                    //是unicode字符
                    case 'u':
                        if (!parse_unicode_string(input, buffer))
                            return TinyJsonParseRet::TINY_JSON_PARSE_FAIL;
                        break;
                    //非以上字符，出现在\后面，例如（"\"\\d\""）,则是非法的
                    default:
                        return TinyJsonParseRet::TINY_JSON_PARSE_FAIL;
                        break;
                    }
                    break;
                default:
                    //小于0x20是控制字符，不可能出现在字符串中
                    if (static_cast<unsigned char>(ch) < 0x20)
                    {
                        return TinyJsonParseRet::TINY_JSON_PARSE_FAIL;
                    }
                    //普通字符，保存在buffer中
                    else
                    {
                        buffer.push_back(ch);
                    }
                    break;
                }
            }
        }
        return TinyJsonParseRet::TINY_JSON_PARSE_FAIL;
    }

    TinyJsonParseRet TinyJsonReader::parse_array(std::istream &input, TinyJsonValue &value)
    {
        //如果开头匹配不到'['
        if (!try_match_char(input, '['))
            return TinyJsonParseRet::TINY_JSON_PARSE_FAIL;

        //如果匹配到']'，表示是空数组
        if (try_match_char(input, ']'))
        {
            value.set_type(TinyJsonType::TINY_JSON_ARRAY);
            value.m_values.m_array_value = std::make_shared<Array>();
            return TinyJsonParseRet::TINY_JSON_PARSE_SECCESS;
        }

        TinyJsonParseRet ret;
        value.m_values.m_array_value = std::make_shared<Array>();
        //以逗号为分割,解析数组中的每个元素
        do
        {
            TinyJsonValuePtr v = std::make_shared<TinyJsonValue>();
            ret = parse_tinyjsonvalue(input, *v);
            //如果某个元素解析失败，跳出循环
            if (ret == TinyJsonParseRet::TINY_JSON_PARSE_FAIL)
            {
                break;
            }
            //某个元素解析成功，添加到数组
            value.m_values.m_array_value->push_back(v);
        } while (try_match_char(input, ','));

        //解析完元素后，如果匹配不到']'
        if (!try_match_char(input, ']'))
        {
            value.reset();
            return TinyJsonParseRet::TINY_JSON_PARSE_FAIL;
        }
        //如果解析成功
        if (ret == TinyJsonParseRet::TINY_JSON_PARSE_SECCESS)
        {
            value.set_type(TinyJsonType::TINY_JSON_ARRAY);
        }
        else
        //如果解析失败，指针置0
        //这里指针不置0，也不会引起内存泄漏，因为使用的是智能指针
        //置0主要是防止野指针
        {
            value.reset();
        }
        return ret;
    }

    TinyJsonParseRet TinyJsonReader::parse_object(std::istream &input, TinyJsonValue &value)
    {
        //如果开头匹配不到'{'
        if (!try_match_char(input, '{'))
            return TinyJsonParseRet::TINY_JSON_PARSE_FAIL;

        //如果匹配到'}'，表示是空数组
        if (try_match_char(input, '}'))
        {
            value.set_type(TinyJsonType::TINY_JSON_OBJECT);
            value.m_values.m_object_value = std::make_shared<Object>();
            return TinyJsonParseRet::TINY_JSON_PARSE_SECCESS;
        }

        TinyJsonParseRet ret;
        value.m_values.m_object_value = std::make_shared<Object>();
        //以逗号为分割,解析对象中的每对key-value
        do
        {
            String key;
            //如果解析key失败
            if (!parse_key(input, key))
            {
                ret = TinyJsonParseRet::TINY_JSON_PARSE_FAIL;
                break;
            }

            //如果匹配不到":"
            if (!try_match_char(input, ':'))
            {
                ret = TinyJsonParseRet::TINY_JSON_PARSE_FAIL;
                break;
            }

            //解析value
            TinyJsonValuePtr v = std::make_shared<TinyJsonValue>();
            ret = parse_tinyjsonvalue(input, *v);
            //如果某个value解析失败，跳出循环
            if (ret == TinyJsonParseRet::TINY_JSON_PARSE_FAIL)
            {
                break;
            }
            //某个key—value解析成功，添加到对象
            value.m_values.m_object_value->insert(std::make_pair(key, v));
        } while (try_match_char(input, ','));

        //解析完元素后，如果匹配不到'}'
        if (!try_match_char(input, '}'))
        {
            value.reset();
            return TinyJsonParseRet::TINY_JSON_PARSE_FAIL;
        }
        //如果解析成功
        if (ret == TinyJsonParseRet::TINY_JSON_PARSE_SECCESS)
        {
            value.set_type(TinyJsonType::TINY_JSON_OBJECT);
        }
        else
        //如果解析失败，指针置0
        //这里指针不置0，也不会引起内存泄漏，因为使用的是智能指针
        //置0主要是防止野指针
        {
            value.reset();
        }
        return ret;
    }

    Boolean TinyJsonReader::parse_key(std::istream &input, String &key)
    {
        char dilimiter = '\"';
        char ch = 0;

        if (!try_match_char(input, dilimiter))
        {
            return false;
        }

        String buffer;
        while (input.good() && !input.eof())
        {
            input.get(ch);
            if (input.eof())
                return false;

            if (ch == dilimiter)
            {
                buffer.erase(0, buffer.find_first_not_of(" "));
                buffer.erase(buffer.find_last_not_of(' ') + 1);
                if (buffer.empty())
                    return false;
                key = buffer;
                return true;
            }
            else
            {
                if (static_cast<unsigned int>(ch) < 0x20)
                    return false;
                else
                    buffer.push_back(ch);
            }
        }
        return false;
    }
}